home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / devices / msh_1_5 / part03 < prev    next >
Internet Message Format  |  1990-02-21  |  42KB

  1. Path: xanth!cs.odu.edu!Amiga-Request
  2. From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v90i081: MSH 1.5 - Messydos File System Handler , Part03/06
  5. Message-ID: <11500@xanth.cs.odu.edu>
  6. Date: 21 Feb 90 01:59:44 GMT
  7. Sender: tadguy@cs.odu.edu
  8. Reply-To: Olaf 'Rhialto' Seibert <U211344%HNYKUN11.BITNET@CUNYVM.CUNY.EDU>
  9. Lines: 1734
  10. Approved: tadguy@cs.odu.edu (Tad Guy)
  11. X-Mail-Submissions-To: Amiga@cs.odu.edu
  12. X-Post-Discussions-To: comp.sys.amiga
  13.  
  14. Submitted-by: Olaf 'Rhialto' Seibert <U211344%HNYKUN11.BITNET@CUNYVM.CUNY.EDU>
  15. Posting-number: Volume 90, Issue 081
  16. Archive-name: devices/msh-1.5/part03
  17.  
  18. #!/bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 3 (of 6)."
  25. # Contents:  src/device.c src/hansec.c
  26. # Wrapped by tadguy@xanth on Tue Feb 20 20:57:10 1990
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'src/device.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'src/device.c'\"
  30. else
  31. echo shar: Extracting \"'src/device.c'\" \(18725 characters\)
  32. sed "s/^X//" >'src/device.c' <<'END_OF_FILE'
  33. X/*-
  34. X * $Id: device.c,v 1.5 90/01/27 20:34:43 Rhialto Exp $
  35. X * $Log:    device.c,v $
  36. X * Revision 1.5  90/01/27  20:34:43  Rhialto
  37. X * Commented out #undef DEBUG
  38. X * 
  39. X * Revision 1.4  90/01/23  00:24:50  Rhialto
  40. X * io_Error=0 for immediate commands
  41. X *
  42. X * Revision 1.3  89/12/17  21:29:37  Rhialto
  43. X * Revision 1.1  89/12/17  20:03:55  Rhialto
  44. X *
  45. X * DEVICE.C
  46. X *
  47. X * The messydisk.device code that makes it a real Exec .device.
  48. X * Mostly based on the 1.1 RKM example and Matt Dillon's library code.
  49. X *
  50. X * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  51. X * not be used or copied without a licence.
  52. X-*/
  53. X
  54. X#include "dev.h"
  55. X#include "device.h"
  56. X
  57. X/*#undef DEBUG            /**/
  58. X#ifdef DEBUG
  59. X#   define    debug(x)  dbprintf x
  60. X#else
  61. X#   define    debug(x)
  62. X#endif
  63. X
  64. X/*
  65. X * The first executable location. This should return an error in case
  66. X * someone tried to run you as a program (instead of loading you as a
  67. X * device)
  68. X */
  69. X/* INDENT OFF */
  70. X#asm
  71. X    moveq.l #20,d0
  72. X    rts
  73. X#endasm
  74. X/* INDENT ON */
  75. X
  76. X/*
  77. X * A romtag structure. Both "exec" and "ramlib" look for this structure to
  78. X * discover magic constants about you (such as where to start running you
  79. X * from...).
  80. X */
  81. X/* INDENT OFF */
  82. X#asm
  83. X    public    __H0_end
  84. X_EndCode equ    __H0_end
  85. X    public    _RomTag
  86. X_RomTag:
  87. X    dc.w    $4AFC        ; RTC_MATCHWORD
  88. X    dc.l    _RomTag     ; rt_MatchTag
  89. X    dc.l    __H0_end    ; rt_EndSkip
  90. X    dc.b    0        ; rt_Flags (no RTF_AUTOINIT)
  91. X    dc.b    VERSION     ; rt_Version
  92. X    dc.b    3        ; rt_Type  NT_DEVICE
  93. X    dc.b    RTPRI        ; rt_Pri
  94. X    dc.l    _DevName    ; rt_Name
  95. X    dc.l    _idString    ; rt_IdString
  96. X    dc.l    _Init        ; rt_Init
  97. X#endasm
  98. X/* INDENT ON */
  99. X
  100. Xchar        DevName[] = "messydisk.device";
  101. Xchar        idString[] = "messydisk.device $Revision: 1.5 $ $Date: 90/01/27 20:34:43 $\r\n";
  102. X
  103. X/*
  104. X * -30-6*X  Library vectors:
  105. X */
  106. X
  107. Xvoid        (*LibVectors[]) () =
  108. X{
  109. X    _DevOpen, _DevClose, _DevExpunge, _LibNull,
  110. X
  111. X    _DevBeginIO,
  112. X    _DevAbortIO,
  113. X    (void (*) ()) -1
  114. X};
  115. X
  116. X/*
  117. X * Device commands:
  118. X */
  119. X
  120. Xvoid        (*funcTable[]) () = {
  121. X    CMD_Invalid, CMD_Reset, CMD_Read, CMD_Write, CMD_Update, CMD_Clear,
  122. X    CMD_Stop, CMD_Start, CMD_Flush, TD_Motor, TD_Seek, TD_Format,
  123. X    TD_Remove, TD_Changenum, TD_Changestate, TD_Protstatus, TD_Rawread,
  124. X    TD_Rawwrite, TD_Getdrivetype, TD_Getnumtracks, TD_Addchangeint,
  125. X    TD_Remchangeint,
  126. X};
  127. X
  128. X/*
  129. X * Here begin the system interface commands. When the user calls
  130. X * OpenDevice/CloseDevice/RemDevice, this eventually gets trahslated into
  131. X * a call to the following routines (Open/Close/Expunge).  Exec has
  132. X * already put our device pointer in A6 for us.  Exec has turned off task
  133. X * switching while in these routines (via Forbid/Permit), so we should not
  134. X * take too long in them.
  135. X */
  136. X/* INDENT OFF */
  137. X#asm
  138. X    public    _Init
  139. X_Init:                ;a0=segment list
  140. X    movem.l D2-D3/A0/A6,-(sp)
  141. X    jsr    _CInit
  142. X    movem.l (sp)+,D2-D3/A0/A6
  143. X    rts
  144. X
  145. X    public    __DevOpen
  146. X__DevOpen:            ;d0=unitnum,d1=flags,a1=ioreq,a6=device
  147. X    movem.l D0-D3/A1/A6,-(sp)
  148. X    jsr    _DevOpen
  149. X    movem.l (sp)+,D0-D3/A1/A6
  150. X    rts
  151. X
  152. X    public    __DevClose
  153. X__DevClose:            ;a1=ioreq,a6=device
  154. X    movem.l D2-D3/A1/A6,-(sp)
  155. X    jsr    _DevClose
  156. X    movem.l (sp)+,D2-D3/A1/A6
  157. X    rts
  158. X
  159. X    public    __DevExpunge
  160. X__DevExpunge:            ;a6=device
  161. X    movem.l D2-D3/A6,-(sp)
  162. X    jsr    _DevExpunge
  163. X    movem.l (sp)+,D2-D3/A6
  164. X    rts
  165. X
  166. X    public    __LibNull
  167. X__LibNull:
  168. X    clr.l    d0
  169. X    rts
  170. X
  171. X    public    __DevBeginIO
  172. X__DevBeginIO:            ;a1=ioreq,a6=device
  173. X    movem.l D2-D3/A1/A6,-(sp)
  174. X    jsr    _DevBeginIO
  175. X    movem.l (sp)+,D2-D3/A1/A6
  176. X    rts
  177. X
  178. X    public    __DevAbortIO
  179. X__DevAbortIO:            ;a1=ioreq,a6=device
  180. X    movem.l D2-D3/A1/A6,-(sp)
  181. X    jsr    _DevAbortIO
  182. X    movem.l (sp)+,D2-D3/A1/A6
  183. X    rts
  184. X#endasm
  185. X
  186. X#ifdef HANDLE_IO_QUICK
  187. X#asm
  188. X;;;;
  189. X;
  190. X;   C interface to the atomic set bit and test old value instruction.
  191. X;
  192. X;   Called as    BSET_ACTIVE(byte *address).
  193. X;
  194. X;   Old value of the bit returned all over d0.w
  195. X
  196. X_BSET_ACTIVE:
  197. X    move.l    4(sp),a0
  198. X    bset    #0,(a0)         ; UNITB_ACTIVE
  199. X    sne    d0
  200. X    rts
  201. X
  202. X#endasm
  203. X#endif
  204. X/* INDENT ON */
  205. X
  206. Xlong        SysBase;    /* Argh! A global variable! */
  207. X
  208. X/*
  209. X * The Initialization routine is given only a seglist pointer.    Since we
  210. X * are NOT AUTOINIT we must construct and add the device ourselves and
  211. X * return either NULL or the device pointer.  Exec has Forbid() for us
  212. X * during the call.
  213. X *
  214. X * If you have an extended device structure you must specify the size of the
  215. X * extended structure in MakeLibrary().
  216. X */
  217. X
  218. XDEV           *
  219. XCInit(D2, D3, segment)
  220. Xulong        D2,
  221. X        D3;
  222. Xlong        segment;
  223. X{
  224. X    DEV        *dev;
  225. X
  226. X    SysBase = *(long *) 4;
  227. X#ifdef DEBUG
  228. X    dbinit();
  229. X#endif
  230. X    dev = MakeLibrary(LibVectors, NULL, NULL, (long) sizeof (DEV), NULL);
  231. X    if (DevInit(dev)) {
  232. X    dev->dev_Node.ln_Type = NT_DEVICE;
  233. X    dev->dev_Node.ln_Name = DevName;
  234. X    dev->dev_Flags = LIBF_CHANGED | LIBF_SUMUSED;
  235. X    dev->dev_Version = VERSION;
  236. X    dev->dev_Revision = REVISION;
  237. X    dev->dev_IdString = (APTR) idString;
  238. X    dev->md_Seglist = segment;
  239. X    AddDevice(dev);
  240. X    return (dev);
  241. X    }
  242. X    FreeMem((char *) dev - dev->dev_NegSize, dev->dev_NegSize + dev->dev_PosSize);
  243. X    return NULL;
  244. X}
  245. X
  246. X/*
  247. X * Open is given the device pointer, unitno and flags.    Either return the
  248. X * device pointer or NULL.  Remove the DELAYED-EXPUNGE flag. Exec has
  249. X * Forbid() for us during the call.
  250. X */
  251. X
  252. Xvoid
  253. XDevOpen(unitno, flags, D2, D3, ioreq, dev)
  254. Xulong        unitno;
  255. Xulong        flags;
  256. Xulong        D2,
  257. X        D3;
  258. Xstruct IOStdReq *ioreq;
  259. XDEV           *dev;
  260. X{
  261. X    UNIT       *unit;
  262. X
  263. X    debug(("OpenDevice unit %ld, flags %lx\n", unitno, flags));
  264. X    if (unitno >= MD_NUMUNITS)
  265. X    goto error;
  266. X
  267. X    if ((unit = dev->md_Unit[unitno]) == NULL) {
  268. X    if ((unit = UnitInit(dev, unitno)) == NULL)
  269. X        goto error;
  270. X    dev->md_Unit[unitno] = unit;
  271. X    }
  272. X    ioreq->io_Unit = (struct Unit *) unit;
  273. X
  274. X    ++unit->mu_OpenCnt;
  275. X    ++dev->dev_OpenCnt;
  276. X    dev->dev_Flags &= ~LIBF_DELEXP;
  277. X
  278. X    return;
  279. X
  280. Xerror:
  281. X    ioreq->io_Error = IOERR_OPENFAIL;
  282. X}
  283. X
  284. X/*
  285. X * Close is given the device pointer and the io request.  Be sure not to
  286. X * decrement the open count if already zero.    If the open count is or
  287. X * becomes zero AND there is a LIBF_DELEXP, we expunge the device and
  288. X * return the seglist.    Otherwise we return NULL.
  289. X *
  290. X * Note that this routine never sets LIBF_DELEXP on its own.
  291. X *
  292. X * Exec has Forbid() for us during the call.
  293. X */
  294. X
  295. Xlong
  296. XDevClose(D2, D3, ioreq, dev)
  297. Xulong        D2,
  298. X        D3;
  299. Xstruct IOStdReq *ioreq;
  300. XDEV           *dev;
  301. X{
  302. X    UNIT       *unit;
  303. X
  304. X    unit = (UNIT *) ioreq->io_Unit;
  305. X    debug(("CloseDevice io %08lx unit %08lx\n", ioreq, unit));
  306. X
  307. X    /*
  308. X     * See if the unit is still in use. If not, close it down. This may
  309. X     * need to do an update, which requires the ioreq.
  310. X     */
  311. X
  312. X    if (unit->mu_OpenCnt && --unit->mu_OpenCnt == 0) {
  313. X    dev->md_Unit[unit->mu_UnitNr] = NULL;
  314. X    UnitCloseDown(ioreq, dev, unit);
  315. X    }
  316. X    /*
  317. X     * Make sure the ioreq is not used again.
  318. X     */
  319. X    ioreq->io_Unit = (void *) -1;
  320. X    ioreq->io_Device = (void *) -1;
  321. X
  322. X    if (dev->dev_OpenCnt && --dev->dev_OpenCnt)
  323. X    return (NULL);
  324. X    if (dev->dev_Flags & LIBF_DELEXP)
  325. X    return (DevExpunge(D2, D3, dev));
  326. X    return (NULL);
  327. X}
  328. X
  329. X/*
  330. X * We expunge the device and return the Seglist ONLY if the open count is
  331. X * zero. If the open count is not zero we set the DELAYED-EXPUNGE
  332. X * flag and return NULL.
  333. X *
  334. X * Exec has Forbid() for us during the call.  NOTE ALSO that Expunge might be
  335. X * called from the memory allocator and thus we CANNOT DO A Wait() or
  336. X * otherwise take a long time to complete (straight from RKM).
  337. X *
  338. X * Apparently RemLibrary(lib) calls our expunge routine and would therefore
  339. X * freeze if we called it ourselves.  As far as I can tell from RKM,
  340. X * DevExpunge(lib) must remove the device itself as shown below.
  341. X */
  342. X
  343. Xlong
  344. XDevExpunge(D2, D3, dev)
  345. Xulong        D2,
  346. X        D3;
  347. XDEV           *dev;
  348. X{
  349. X    long        Seglist;
  350. X
  351. X    if (dev->dev_OpenCnt) {
  352. X    dev->dev_Flags |= LIBF_DELEXP;
  353. X    return (NULL);
  354. X    }
  355. X    Remove(dev);
  356. X    DevCloseDown(dev);          /* Should be quick! */
  357. X#ifdef DEBUG
  358. X    dbuninit();
  359. X#endif
  360. X    Seglist = dev->md_Seglist;
  361. X    FreeMem((char *) dev - dev->dev_NegSize,
  362. X        (long) dev->dev_NegSize + dev->dev_PosSize);
  363. X    return (Seglist);
  364. X}
  365. X
  366. X/*
  367. X * BeginIO entry point. We don't handle any QUICK requests, we just send
  368. X * the request to the proper unit to handle.
  369. X */
  370. X
  371. Xvoid
  372. XDevBeginIO(D2, D3, ioreq, dev)
  373. Xulong        D2,
  374. X        D3;
  375. Xregister struct IOStdReq *ioreq;
  376. XDEV           *dev;
  377. X{
  378. X    UNIT       *unit;
  379. X
  380. X    /*
  381. X     * Bookkeeping.
  382. X     */
  383. X    unit = (UNIT *) ioreq->io_Unit;
  384. X    debug(("BeginIO: io %08lx dev %08lx u %08lx\n", ioreq, dev, unit));
  385. X
  386. X    /*
  387. X     * See if the io command is within range.
  388. X     */
  389. X    if (STRIP(ioreq->io_Command) > TD_LASTCOMM)
  390. X    goto NoCmd;
  391. X
  392. X#ifdef HANDLE_IO_QUICK
  393. X    Forbid();                   /* Disable(); is a bit too strong for us. */
  394. X#endif
  395. X
  396. X    /*
  397. X     * Process all immediate commands no matter what. Don't even require
  398. X     * an exclusive lock on the unit.
  399. X     */
  400. X    if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  401. X    goto Immediate;
  402. X
  403. X    /*
  404. X     * We don't handle any QUICK I/O since that only gives trouble with
  405. X     * message ports and so. Other devices normally would include the code
  406. X     * below.
  407. X     */
  408. X#ifdef HANDLE_IO_QUICK
  409. X    /*
  410. X     * See if the user does not request QUICK IO. If not, it is likely to
  411. X     * be async and therefore we don't do it sync.
  412. X     */
  413. X    if (!(ioreq->io_Flags & IOF_QUICK))
  414. X    goto NoQuickRequested;
  415. X
  416. X    /*
  417. X     * See if the unit is STOPPED. If so, queue the msg.
  418. X     */
  419. X    if (unit->mu_Flags & UNITF_STOPPED)
  420. X    goto QueueMsg;
  421. X
  422. X    /*
  423. X     * This is not an immediate command. See if the device is busy. If
  424. X     * not, process the action in this (the caller's) context.
  425. X     */
  426. X    if (!BSET_ACTIVE(&unit->mu_Flags))
  427. X    goto Immediate;
  428. X#endif
  429. X
  430. X    /*
  431. X     * We need to queue the device. Clear the QUICK flag.
  432. X     */
  433. XQueueMsg:
  434. X    ioreq->io_Flags &= ~IOF_QUICK;
  435. XNoQuickRequested:
  436. X#ifdef HANDLE_IO_QUICK
  437. X    Permit();                   /* Enable(); is a bit too strong for us. */
  438. X#endif
  439. X    PutMsg(&unit->mu_Port, ioreq);
  440. X
  441. X    return;
  442. X
  443. XImmediate:
  444. X#ifdef HANDLE_IO_QUICK
  445. X    Permit();                   /* Enable(); is a bit too strong for us. */
  446. X#endif
  447. X    debug(("BeginIO: Immediate\n"));
  448. X    ioreq->io_Error = TDERR_NoError;
  449. X    PerformIO(ioreq, unit);
  450. X    return;
  451. X
  452. XNoCmd:
  453. X    ioreq->io_Error = IOERR_NOCMD;
  454. X    TermIO(ioreq);
  455. X    return;
  456. X
  457. X}
  458. X
  459. X/*
  460. X * Terminate an io request. Called (normally) for every BeginIO. 'Funny'
  461. X * commands that don't call TermIO, or call it multiple times, may not be
  462. X * properly handled unless you are careful. TD_ADDCHANGEINT and
  463. X * TD_REMCHANGEINT are obvious examples.
  464. X */
  465. X
  466. Xvoid
  467. XTermIO(ioreq)
  468. Xregister struct IOStdReq *ioreq;
  469. X{
  470. X    register UNIT  *unit;
  471. X
  472. X    unit = (UNIT *) ioreq->io_Unit;
  473. X    debug(("TermIO: io %08lx u %08lx %ld %d\n", ioreq, unit,
  474. X       ioreq->io_Actual, ioreq->io_Error));
  475. X
  476. X#ifdef HANDLE_IO_QUICK
  477. X    /*
  478. X     * Since immediate commands don't even require an exclusive lock on
  479. X     * the unit, don't unlock it.
  480. X     */
  481. X    if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  482. X    goto Immediate;
  483. X
  484. X    /*
  485. X     * We may need to turn the active (lock) bit off, but not if we are
  486. X     * within the task.
  487. X     */
  488. X    if (unit->mu_Flags & UNITF_INTASK)
  489. X    goto Immediate;
  490. X
  491. X    unit->mu_Flags &= ~UNITF_ACTIVE;
  492. X
  493. X    /*
  494. X     * The task may have work to do that came in while we were processing
  495. X     * in the caller's context.
  496. X     */
  497. X    if (unit->mu_Flags & UNITF_WAKETASK) {
  498. X    unit->mu_Flags &= ~UNITF_WAKETASK;
  499. X    WakePort(&unit->mu_Port);
  500. X    }
  501. X#endif
  502. X
  503. XImmediate:
  504. X    /*
  505. X     * If the quick bit is still set then wen don't need to reply the msg
  506. X     * -- just return to the user.
  507. X     */
  508. X
  509. X    if (!(ioreq->io_Flags & IOF_QUICK))
  510. X    ReplyMsg(&ioreq->io_Message);
  511. X
  512. X    return;
  513. X}
  514. X
  515. X/*
  516. X * AbortIO entry point. We don't abort IO here.
  517. X */
  518. X
  519. Xlong
  520. XDevAbortIO(D2, D3, ioreq, dev)
  521. Xulong        D2,
  522. X        D3;
  523. XDEV           *dev;
  524. Xstruct IOStdReq *ioreq;
  525. X{
  526. X    return 1;
  527. X}
  528. X
  529. Xvoid
  530. XWakePort(port)
  531. Xregister struct MsgPort *port;
  532. X{
  533. X    Signal(port->mp_SigTask, 1L << port->mp_SigBit);
  534. X}
  535. X
  536. X/*
  537. X * This is the main loop of the Unit tasks. It must be very careful with
  538. X * global data.
  539. X */
  540. X
  541. Xvoid
  542. XUnitTask()
  543. X{
  544. X    /* DEV *dev; */
  545. X    UNIT       *unit;
  546. X    long        waitmask;
  547. X    struct IOExtTD *ioreq;
  548. X
  549. X    {
  550. X    struct Task    *task,
  551. X               *FindTask();
  552. X
  553. X    task = FindTask(NULL);
  554. X    unit = (UNIT *) task->tc_UserData;
  555. X    /* dev = unit->mu_Dev; */
  556. X    task->tc_UserData = NULL;
  557. X    }
  558. X
  559. X    /*
  560. X     * Now finish initializing the message ports and other signal things
  561. X     */
  562. X
  563. X    {
  564. X    byte        sigbit;
  565. X
  566. X    unit->mu_DiskReplyPort.mp_SigBit = AllocSignal(-1L);
  567. X    unit->mu_DiskReplyPort.mp_Flags = PA_SIGNAL;
  568. X
  569. X    sigbit = AllocSignal(-1L);
  570. X    unit->mu_Port.mp_SigBit = sigbit;
  571. X    unit->mu_Port.mp_Flags = PA_SIGNAL;
  572. X    waitmask = 1L << sigbit;
  573. X
  574. X    unit->mu_DmaSignal = AllocSignal(-1L);
  575. X    }
  576. X
  577. X    for (;;) {
  578. X    debug(("Task: Waiting... "));
  579. X    Wait(waitmask);
  580. X
  581. X    /*
  582. X     * See if we are stopped.
  583. X     */
  584. X    if (unit->mu_Flags & UNITF_STOPPED)
  585. X        continue;
  586. X
  587. X#ifdef HANDLE_IO_QUICK
  588. X    /*
  589. X     * Lock the device. If it fails, we have set a flag such that the
  590. X     * TermIO wakes us again.
  591. X     */
  592. X    unit->mu_Flags |= UNITF_WAKETASK;
  593. X    if (BSET_ACTIVE(&unit->mu_Flags))
  594. X        continue;
  595. X
  596. X    unit->mu_Flags |= UNITF_INTASK;
  597. X#endif
  598. X
  599. X    while (ioreq = (struct IOExtTD *) GetMsg(&unit->mu_Port)) {
  600. X        debug(("Task: io %08lx %x\n", ioreq, ioreq->iotd_Req.io_Command));
  601. X        ioreq->iotd_Req.io_Error = 0;
  602. X        PerformIO((&ioreq->iotd_Req), unit);
  603. X    }
  604. X
  605. X#ifdef HANDLE_IO_QUICK
  606. X    unit->mu_Flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
  607. X#endif
  608. X    }
  609. X}
  610. X
  611. Xvoid
  612. XCMD_Invalid(ioreq, unit)
  613. Xstruct IOStdReq *ioreq;
  614. XUNIT           *unit;
  615. X{
  616. X    ioreq->io_Error = IOERR_NOCMD;
  617. X    TermIO(ioreq);
  618. X}
  619. X
  620. Xvoid
  621. XCMD_Stop(ioreq, unit)
  622. Xstruct IOExtTD *ioreq;
  623. XUNIT           *unit;
  624. X{
  625. X    unit->mu_Flags |= UNITF_STOPPED;
  626. X    TermIO(ioreq);
  627. X}
  628. X
  629. Xvoid
  630. XCMD_Start(ioreq, unit)
  631. Xstruct IOExtTD *ioreq;
  632. XUNIT           *unit;
  633. X{
  634. X    unit->mu_Flags &= ~UNITF_STOPPED;
  635. X    WakePort(&unit->mu_Port);
  636. X    TermIO(ioreq);
  637. X}
  638. X
  639. Xvoid
  640. XCMD_Flush(ioreq, unit)
  641. Xstruct IOExtTD *ioreq;
  642. XUNIT           *unit;
  643. X{
  644. X    register struct IOStdReq *req;
  645. X
  646. X    /* Flush our own command queue */
  647. X    Forbid();
  648. X    while (req = (struct IOStdReq *) GetMsg(unit->mu_Port)) {
  649. X    req->io_Error = IOERR_ABORTED;
  650. X    ReplyMsg(&req->io_Message);
  651. X    }
  652. X    Permit();
  653. X
  654. X    WakePort(&unit->mu_Port);
  655. X    TermIO(ioreq);
  656. X}
  657. X
  658. Xvoid
  659. XTrackdiskGateway(ioreq, unit)
  660. Xregister struct IOExtTD *ioreq;
  661. XUNIT           *unit;
  662. X{
  663. X    register struct IOExtTD *tdioreq;
  664. X
  665. X    debug(("Trackdisk: %x ", ioreq->iotd_Req.io_Command));
  666. X    tdioreq = unit->mu_DiskIOReq;
  667. X
  668. X    /*
  669. X     * Clone almost the entire io request to relay to the
  670. X     * trackdisk.device.
  671. X     */
  672. X
  673. X    tdioreq->iotd_Req.io_Command = ioreq->iotd_Req.io_Command;
  674. X    tdioreq->iotd_Req.io_Flags = ioreq->iotd_Req.io_Flags | IOF_QUICK;
  675. X    tdioreq->iotd_Req.io_Length = ioreq->iotd_Req.io_Length;
  676. X    tdioreq->iotd_Req.io_Data = ioreq->iotd_Req.io_Data;
  677. X    tdioreq->iotd_Req.io_Offset = ioreq->iotd_Req.io_Offset;
  678. X    if (ioreq->iotd_Req.io_Command & TDF_EXTCOM) {
  679. X    tdioreq->iotd_Count = ioreq->iotd_Count;
  680. X    tdioreq->iotd_SecLabel = ioreq->iotd_SecLabel;
  681. X    }
  682. X    BeginIO(tdioreq);
  683. X    WaitIO(tdioreq);
  684. X
  685. X    ioreq->iotd_Req.io_Error = tdioreq->iotd_Req.io_Error;
  686. X    ioreq->iotd_Req.io_Actual = tdioreq->iotd_Req.io_Actual;
  687. X
  688. X    TermIO(ioreq);
  689. X}
  690. X
  691. X#ifdef DEBUG
  692. X/* DEBUGGING                */
  693. Xstruct MsgPort *Dbport;     /* owned by the debug process        */
  694. Xstruct MsgPort *Dback;        /* owned by the DOS device driver  */
  695. Xshort        DBEnable;
  696. Xstruct SignalSemaphore PortUse;
  697. X
  698. X#define CTOB(x) (void *)(((long)(x))>>2)        /* BCPL conversion */
  699. X
  700. X/*
  701. X * DEBUGGING CODE.    You cannot make DOS library calls that access
  702. X * other devices from within a device driver because the caller may not be
  703. X * a process.  If you need to make such calls you must create a port and
  704. X * construct the DOS messages yourself.  I do not do this.  To get
  705. X * debugging info out another PROCESS is created to which debugging
  706. X * messages can be sent. The replyport gets a new SigTask for every
  707. X * dbprintf call, therefore the semaphore.
  708. X */
  709. X
  710. Xextern void    debugproc();
  711. Xstruct Library *DOSBase,
  712. X           *OpenLibrary();
  713. X
  714. Xdbinit()
  715. X{
  716. X    struct Task    *task = FindTask(NULL);
  717. X
  718. X    DOSBase = OpenLibrary("dos.library", 0L);
  719. X    Dback = CreatePort("Dback", -1L);
  720. X    FreeSignal((long) Dback->mp_SigBit);
  721. X    Dback->mp_SigBit = 2;
  722. X    InitSemaphore(&PortUse);
  723. X    CreateProc("messydisk_DB", (long) TASKPRI + 1, CTOB(debugproc), 2000L);
  724. X    WaitPort(Dback);            /* handshake startup    */
  725. X    GetMsg(Dback);              /* remove dummy msg     */
  726. X    DBEnable = 1;
  727. X    dbprintf("Debugger running V1.11\n");
  728. X}
  729. X
  730. Xdbuninit()
  731. X{
  732. X    struct Message  killmsg;
  733. X
  734. X    if (Dbport) {
  735. X    killmsg.mn_Length = 0;    /* 0 means die        */
  736. X    ObtainSemaphore(&PortUse);
  737. X    Dback->mp_SigTask = FindTask(NULL);
  738. X    PutMsg(Dbport, &killmsg);
  739. X    WaitPort(Dback);        /* He's dead jim!      */
  740. X    GetMsg(Dback);
  741. X    ReleaseSemaphore(&PortUse);
  742. X    Dback->mp_SigBit = -1;
  743. X    DeletePort(Dback);
  744. X
  745. X    /*
  746. X     * Since the debug process is running at a greater priority, I am
  747. X     * pretty sure that it is guarenteed to be completely removed
  748. X     * before this task gets control again.
  749. X     */
  750. X    }
  751. X    CloseLibrary(DOSBase);
  752. X}
  753. X
  754. Xdbprintf(a, b, c, d, e, f, g, h, i, j)
  755. Xlong        a, b, c, d, e, f, g, h, i, j;
  756. X{
  757. X    struct {
  758. X    struct Message    msg;
  759. X    char        buf[256];
  760. X    }            msgbuf;
  761. X    register struct Message *msg = &msgbuf.msg;
  762. X    register long   len;
  763. X
  764. X    if (Dbport && DBEnable) {
  765. X    ObtainSemaphore(&PortUse);      /* sprintf is not re-entrant */
  766. X    sprintf(msgbuf.buf, a, b, c, d, e, f, g, h, i, j);
  767. X    len = strlen(msgbuf.buf) + 1;
  768. X    msg->mn_Length = len;    /* Length NEVER 0     */
  769. X    Dback->mp_SigTask = FindTask(NULL);
  770. X    PutMsg(Dbport, msg);
  771. X    WaitPort(Dback);
  772. X    GetMsg(Dback);
  773. X    ReleaseSemaphore(&PortUse);
  774. X    }
  775. X}
  776. X
  777. X/*
  778. X * BTW, the DOS library used by debugmain() was actually opened by the
  779. X * opener of the device driver.
  780. X */
  781. X
  782. Xdebugmain()
  783. X{
  784. X    register struct Message *msg;
  785. X    register long   len;
  786. X    register void  *fh,
  787. X           *Open();
  788. X    void       *fh2;
  789. X    struct Message  DummyMsg;
  790. X
  791. X    Dbport = CreatePort("Dbport", -1L);
  792. X    fh = Open("CON:0/20/640/101/Device debug", MODE_NEWFILE);
  793. X    fh2 = Open("PAR:", MODE_OLDFILE);
  794. X    PutMsg(Dback, &DummyMsg);
  795. X    for (;;) {
  796. X    WaitPort(Dbport);
  797. X    msg = GetMsg(Dbport);
  798. X    len = msg->mn_Length;
  799. X    if (len == 0)
  800. X        break;
  801. X    --len;            /* Fix length up     */
  802. X    if (DBEnable & 1)
  803. X        Write(fh, msg + 1, len);
  804. X    if (DBEnable & 2)
  805. X        Write(fh2, msg + 1, len);
  806. X    PutMsg(Dback, msg);
  807. X    }
  808. X    Close(fh);
  809. X    Close(fh2);
  810. X    DeletePort(Dbport);
  811. X    PutMsg(Dback, msg);         /* Kill handshake  */
  812. X}
  813. X
  814. X/*
  815. X * The assembly tag for the DOS process:  CNOP causes alignment problems
  816. X * with the Aztec assembler for some reason.  I assume then, that the
  817. X * alignment is unknown.  Since the BCPL conversion basically zero's the
  818. X * lower two bits of the address the actual code may start anywhere within
  819. X * 8 bytes of address (remember the first longword is a segment pointer
  820. X * and skipped).  Sigh....  (see CreateProc() above).
  821. X */
  822. X/* INDENT OFF */
  823. X#asm
  824. X    public    _debugproc
  825. X    public    _debugmain
  826. X
  827. X    cseg
  828. X_debugproc:
  829. X    nop
  830. X    nop
  831. X    nop
  832. X    nop
  833. X    nop
  834. X    movem.l D2-D7/A2-A6,-(sp)
  835. X    jsr    _debugmain
  836. X    movem.l (sp)+,D2-D7/A2-A6
  837. X    rts
  838. X#endasm
  839. X
  840. X#endif                /* DEBUG */
  841. END_OF_FILE
  842. if test 18725 -ne `wc -c <'src/device.c'`; then
  843.     echo shar: \"'src/device.c'\" unpacked with wrong size!
  844. fi
  845. # end of 'src/device.c'
  846. fi
  847. if test -f 'src/hansec.c' -a "${1}" != "-c" ; then 
  848.   echo shar: Will not clobber existing file \"'src/hansec.c'\"
  849. else
  850. echo shar: Extracting \"'src/hansec.c'\" \(19261 characters\)
  851. sed "s/^X//" >'src/hansec.c' <<'END_OF_FILE'
  852. X/*-
  853. X * $Id: hansec.c,v 1.4 90/02/10 21:30:54 Rhialto Exp $
  854. X * $Log:    hansec.c,v $
  855. X * Revision 1.4  90/02/10  21:30:54  Rhialto
  856. X * Tuned cache a bit.
  857. X * 
  858. X * Revision 1.3  90/01/27  20:20:16  Rhialto
  859. X * Sorted sectors when flushing cache
  860. X *
  861. X * Revision 1.2  90/01/23  02:31:50  Rhialto
  862. X * Add 16-bit FAT support.
  863. X *
  864. X * Revision 1.1  89/12/17  20:02:49  Rhialto
  865. X * Initial revision
  866. X *
  867. X * HANSEC.C
  868. X *
  869. X * The code for the messydos file system handler.
  870. X *
  871. X * Sector-level stuff: read, write, cache, unit conversion.
  872. X * Other interactions (via MyDoIO) with messydisk.device.
  873. X *
  874. X * This code is (C) Copyright 1989,1990 by Olaf Seibert. All rights reserved.
  875. X * May not be used or copied without a licence.
  876. X-*/
  877. X
  878. X#include "han.h"
  879. X#include "dos.h"
  880. X
  881. X/*#undef DEBUG                /**/
  882. X#ifdef DEBUG
  883. X#   define    debug(x)  dbprintf x
  884. X#else
  885. X#   define    debug(x)
  886. X#endif
  887. X
  888. Xstruct MsgPort *DiskReplyPort;
  889. Xstruct IOExtTD *DiskIOReq;
  890. Xstruct IOStdReq *DiskChangeReq;
  891. X
  892. Xstruct DiskParam Disk;
  893. Xbyte           *Fat;
  894. Xshort        FatDirty;    /* Fat must be written to disk */
  895. X
  896. Xshort        error;        /* To put the error value; for Result2 */
  897. Xlong        IDDiskState;    /* InfoData.id_DiskState */
  898. Xlong        IDDiskType;    /* InfoData.id_DiskType */
  899. Xstruct timerequest *TimeIOReq;    /* For motor-off delay */
  900. Xstruct MinList    CacheList;    /* Sector cache */
  901. Xint        CurrentCache;    /* How many cached buffers do we have */
  902. Xint        MaxCache = 5;    /* Maximum amount of cached buffers */
  903. Xlong        CacheBlockSize; /* Size of disk block + overhead */
  904. Xulong        BufMemType;
  905. Xint        DelayState;
  906. X
  907. Xbyte           *Word8086;
  908. X
  909. Xword
  910. XGet8086Word(offset)
  911. Xregister int    offset;
  912. X{
  913. X    return Word8086[offset] | Word8086[offset + 1] << 8;
  914. X}
  915. X
  916. Xword
  917. XOtherEndianWord(oew)
  918. Xword        oew;
  919. X{
  920. X/* INDENT OFF */
  921. X#asm
  922. X    move.w    8(a5),d0
  923. X    rol.w    #8,d0
  924. X#endasm
  925. X    /* INDENT ON */
  926. X    /*
  927. X     * return (oew << 8) | ((oew >> 8) & 0xff);
  928. X     */
  929. X}
  930. X
  931. Xulong
  932. XOtherEndianLong(oel)
  933. Xulong        oel;
  934. X{
  935. X/* INDENT OFF */
  936. X#asm
  937. X    move.l    8(a5),d0
  938. X    rol.w    #8,d0
  939. X    swap    d0
  940. X    rol.w    #8,d0
  941. X#endasm
  942. X    /* INDENT ON */
  943. X    /*
  944. X     * return ((oel &       0xff) << 24) | ((oel &     0xff00) <<  8) |
  945. X     * ((oel &   0xff0000) >>  8) | ((oel & 0xff000000) >> 24);
  946. X     */
  947. X}
  948. X
  949. Xvoid
  950. XOtherEndianMsd(msd)
  951. Xregister struct MsDirEntry *msd;
  952. X{
  953. X    msd->msd_Date = OtherEndianWord(msd->msd_Date);
  954. X    msd->msd_Time = OtherEndianWord(msd->msd_Time);
  955. X    msd->msd_Cluster = OtherEndianWord(msd->msd_Cluster);
  956. X    msd->msd_Filesize = OtherEndianLong(msd->msd_Filesize);
  957. X}
  958. X
  959. Xword
  960. XClusterToSector(cluster)
  961. Xregister word    cluster;
  962. X{
  963. X    return cluster ? Disk.start + cluster * Disk.spc
  964. X    : 0;
  965. X}
  966. X
  967. Xword
  968. XClusterOffsetToSector(cluster, offset)
  969. Xregister word    cluster;
  970. Xregister word    offset;
  971. X{
  972. X    return cluster ? Disk.start + cluster * Disk.spc + offset / Disk.bps
  973. X    : 0;
  974. X}
  975. X
  976. Xword
  977. XDirClusterToSector(cluster)
  978. Xregister word    cluster;
  979. X{
  980. X    return cluster ? Disk.start + cluster * Disk.spc
  981. X    : Disk.rootdir;
  982. X}
  983. X
  984. Xword
  985. XSectorToCluster(sector)
  986. Xregister word    sector;
  987. X{
  988. X    return sector ? (sector - Disk.start) / Disk.spc
  989. X    : 0;
  990. X}
  991. X
  992. X/*
  993. X * Get the next cluster in a chain. Sort-of checks for special entries.
  994. X */
  995. X
  996. Xword
  997. XNextCluster(cluster)
  998. Xword cluster;
  999. X{
  1000. X    register word entry;
  1001. X
  1002. X    return (entry = GetFatEntry(cluster)) >= 0xFFF0 ? FAT_EOF : entry;
  1003. X}
  1004. X
  1005. Xword
  1006. XNextClusteredSector(sector)
  1007. Xword        sector;
  1008. X{
  1009. X    word        next = (sector + 1 - Disk.start) % Disk.spc;
  1010. X
  1011. X    if (next == 0) {
  1012. X    next = NextCluster(SectorToCluster(sector));
  1013. X    return next != FAT_EOF ? ClusterToSector(next)
  1014. X        : SEC_EOF;
  1015. X    } else
  1016. X    return sector + 1;
  1017. X}
  1018. X
  1019. X#ifndef READONLY
  1020. X
  1021. Xword
  1022. XFindFreeSector(prev)
  1023. Xword        prev;
  1024. X{
  1025. X    word freecluster = FindFreeCluster(SectorToCluster(prev));
  1026. X
  1027. X    return freecluster == FAT_EOF ? SEC_EOF : ClusterToSector(freecluster);
  1028. X}
  1029. X
  1030. X#endif
  1031. X
  1032. X/*
  1033. X * Find a specific sector. The cache list is a Least Recently Used stack:
  1034. X * Put it on the head of the cache list. So if it is not used anymore in a
  1035. X * long time, it bubbles to the end of the list, getting a higher chance
  1036. X * of being trashed for re-use.
  1037. X */
  1038. X
  1039. Xstruct CacheSec *
  1040. XFindSecByNumber(number)
  1041. Xregister int    number;
  1042. X{
  1043. X    register struct CacheSec *sec;
  1044. X    register struct CacheSec *nextsec;
  1045. X
  1046. X    debug(("FindSecByNumber %d", number));
  1047. X
  1048. X    for (sec = (void *) CacheList.mlh_Head;
  1049. X     nextsec = (void *) sec->sec_Node.mln_Succ; sec = nextsec) {
  1050. X    if (sec->sec_Number == number) {
  1051. X        debug((" (%x) %lx\n", sec->sec_Refcount, sec));
  1052. X        Remove(sec);
  1053. X        AddHead(&CacheList, &sec->sec_Node);
  1054. X        return sec;
  1055. X    }
  1056. X    }
  1057. X
  1058. X    debug(("; "));
  1059. X    return NULL;
  1060. X}
  1061. X
  1062. Xstruct CacheSec *
  1063. XFindSecByBuffer(buffer)
  1064. Xbyte           *buffer;
  1065. X{
  1066. X    return (struct CacheSec *) (buffer - OFFSETOF(CacheSec, sec_Data));
  1067. X}
  1068. X
  1069. X/*
  1070. X * Get a fresh cache buffer. If we are allowed more cache, we just
  1071. X * allocate memory. Otherwise, we try to find a currently unused buffer.
  1072. X * We start looking at the end of the list, which is the bottom of the LRU
  1073. X * stack. If that fails, allocate more memory anyway. Not that is likely
  1074. X * anyway, since we currently lock only one sector at a time.
  1075. X */
  1076. X
  1077. Xstruct CacheSec *
  1078. XNewCacheSector()
  1079. X{
  1080. X    register struct CacheSec *sec;
  1081. X    register struct CacheSec *nextsec;
  1082. X
  1083. X    debug(("NewCacheSector\n"));
  1084. X
  1085. X    if (CurrentCache < MaxCache) {
  1086. X    if (sec = AllocMem(CacheBlockSize, BufMemType)) {
  1087. X        goto add;
  1088. X    }
  1089. X    }
  1090. X    for (sec = (void *) CacheList.mlh_TailPred;
  1091. X     nextsec = (void *) sec->sec_Node.mln_Pred; sec = nextsec) {
  1092. X    if ((CurrentCache >= MaxCache) && (sec->sec_Refcount == SEC_DIRTY)) {
  1093. X        FreeCacheSector(sec);       /* Also writes it to disk */
  1094. X        continue;
  1095. X    }
  1096. X    if (sec->sec_Refcount == 0)     /* Implies not SEC_DIRTY */
  1097. X        return sec;
  1098. X    }
  1099. X
  1100. X    sec = AllocMem(CacheBlockSize, BufMemType);
  1101. X
  1102. X    if (sec) {
  1103. Xadd:
  1104. X    CurrentCache++;
  1105. X    AddHead(&CacheList, &sec->sec_Node);
  1106. X    } else
  1107. X    error = ERROR_NO_FREE_STORE;
  1108. X
  1109. X    return sec;
  1110. X}
  1111. X
  1112. X/*
  1113. X * Dispose a cached sector, even if it has a non-zero refcount. If it is
  1114. X * dirty, write it out.
  1115. X */
  1116. X
  1117. Xvoid
  1118. XFreeCacheSector(sec)
  1119. Xregister struct CacheSec *sec;
  1120. X{
  1121. X    debug(("FreeCacheSector %d\n", sec->sec_Number));
  1122. X    Remove(sec);
  1123. X#ifndef READONLY
  1124. X    if (sec->sec_Refcount & SEC_DIRTY) {
  1125. X    PutSec(sec->sec_Number, sec->sec_Data);
  1126. X    }
  1127. X#endif
  1128. X    FreeMem(sec, CacheBlockSize);
  1129. X    CurrentCache--;
  1130. X}
  1131. X
  1132. X/*
  1133. X * Create an empty cache list
  1134. X */
  1135. X
  1136. Xvoid
  1137. XInitCacheList()
  1138. X{
  1139. X    extern struct CacheSec *sec;    /* Of course this does not exist... */
  1140. X
  1141. X    NewList(&CacheList);
  1142. X    CurrentCache = 0;
  1143. X    CacheBlockSize = Disk.bps + sizeof (*sec) - sizeof (sec->sec_Data);
  1144. X}
  1145. X
  1146. X/*
  1147. X * Dispose all cached sectors, possibly writing them to disk.
  1148. X */
  1149. X
  1150. Xvoid
  1151. XFreeCacheList()
  1152. X{
  1153. X    register struct CacheSec *sec;
  1154. X
  1155. X    debug(("FreeCacheList, %d\n", CurrentCache));
  1156. X    while (sec = GetHead(&CacheList)) {
  1157. X    FreeCacheSector(sec);
  1158. X    }
  1159. X}
  1160. X
  1161. X/*
  1162. X * Do an insertion sort on tosort in the CacheList. Since it changes the
  1163. X * location in the list, you must fetch it before calling this routine.
  1164. X * The list will become ascending.
  1165. X */
  1166. X
  1167. Xvoid
  1168. XSortSec(tosort)
  1169. Xregister struct CacheSec *tosort;
  1170. X{
  1171. X    register struct CacheSec *sec;
  1172. X    struct CacheSec *nextsec;
  1173. X    register word   secno;
  1174. X
  1175. X    secno = tosort->sec_Number;
  1176. X    debug(("SortSec %d: ", secno));
  1177. X
  1178. X    for (sec = (void *) CacheList.mlh_Head;
  1179. X     nextsec = (void *) sec->sec_Node.mln_Succ; sec = nextsec) {
  1180. X    debug(("%d, ", sec->sec_Number));
  1181. X    if (sec == tosort) {
  1182. X        debug(("\n"));
  1183. X        return;            /* No need to move it away */
  1184. X    }
  1185. X    if (sec->sec_Number > secno)
  1186. X        break;
  1187. X    }
  1188. X    /* Insert before sec */
  1189. X    Remove(tosort);
  1190. X    Insert(&CacheList, tosort, sec->sec_Node.mln_Pred);
  1191. X    debug(("\n"));
  1192. X}
  1193. X
  1194. X/*
  1195. X * Write all dirty cache buffers to disk. They are written from highest to
  1196. X * lowest, and then the FAT is written out.
  1197. X */
  1198. X
  1199. Xvoid
  1200. XMSUpdate(immediate)
  1201. Xint        immediate;
  1202. X{
  1203. X    register struct CacheSec *sec;
  1204. X    register struct CacheSec *nextsec;
  1205. X
  1206. X    debug(("MSUpdate\n"));
  1207. X
  1208. X#ifndef READONLY
  1209. X    if (DelayState & DELAY_DIRTY) {
  1210. X    /*
  1211. X     * First sort all dirty sectors on block number
  1212. X     */
  1213. X    for (sec = (void *) CacheList.mlh_Head;
  1214. X         nextsec = (void *) sec->sec_Node.mln_Succ; sec = nextsec) {
  1215. X        if (sec->sec_Refcount & SEC_DIRTY) {
  1216. X        SortSec(sec);
  1217. X        }
  1218. X    }
  1219. X    /*
  1220. X     * Then do a second (backward) scan to write them out.
  1221. X     */
  1222. X    for (sec = (void *) CacheList.mlh_TailPred;
  1223. X         nextsec = (void *) sec->sec_Node.mln_Pred; sec = nextsec) {
  1224. X        if (sec->sec_Refcount & SEC_DIRTY) {
  1225. X        PutSec(sec->sec_Number, sec->sec_Data);
  1226. X        sec->sec_Refcount &= ~SEC_DIRTY;
  1227. X        }
  1228. X    }
  1229. X    DelayState &= ~DELAY_DIRTY;
  1230. X    }
  1231. X    if (FatDirty) {
  1232. X    WriteFat();
  1233. X    }
  1234. X#endif
  1235. X
  1236. X    if (immediate)
  1237. X    DelayState = DELAY_RUNNING1;
  1238. X
  1239. X    if (DelayState & DELAY_RUNNING2) {
  1240. X    StartTimer();
  1241. X    DelayState &= ~DELAY_RUNNING2;
  1242. X    } else {            /* DELAY_RUNNING1 */
  1243. X#ifndef READONLY
  1244. X    while (TDUpdate() != 0 && RetryRwError(DiskIOReq))
  1245. X        ;
  1246. X#endif
  1247. X    TDMotorOff();
  1248. X    DelayState = DELAY_OFF;
  1249. X    }
  1250. X}
  1251. X
  1252. X/*
  1253. X * Start the timer which triggers cache writing and stopping the disk
  1254. X * motor.
  1255. X */
  1256. X
  1257. Xvoid
  1258. XStartTimer()
  1259. X{
  1260. X    DelayState |= DELAY_RUNNING1 | DELAY_RUNNING2;
  1261. X
  1262. X    if (CheckIO(TimeIOReq)) {
  1263. X    WaitIO(TimeIOReq);
  1264. X    TimeIOReq->tr_node.io_Command = TR_ADDREQUEST;
  1265. X    TimeIOReq->tr_time.tv_secs = 3;
  1266. X    TimeIOReq->tr_time.tv_micro = 0;
  1267. X    SendIO(TimeIOReq);
  1268. X    }
  1269. X}
  1270. X
  1271. X/*
  1272. X * Get a pointer to a logical sector { 0, ..., MS_SECTCNT - 1}. We
  1273. X * allocate a buffer and copy the data in, and lock the buffer until
  1274. X * FreeSec() is called.
  1275. X */
  1276. X
  1277. Xbyte           *
  1278. XGetSec(sector)
  1279. Xint        sector;
  1280. X{
  1281. X    struct CacheSec *sec;
  1282. X
  1283. X    if (sec = FindSecByNumber(sector)) {
  1284. X    sec->sec_Refcount++;
  1285. X
  1286. X    return sec->sec_Data;
  1287. X    }
  1288. X    if (sec = NewCacheSector()) {
  1289. X    register struct IOExtTD *req;
  1290. X
  1291. X    sec->sec_Number = sector;
  1292. X    sec->sec_Refcount = 1;
  1293. X
  1294. X    debug(("GetSec %d\n", sector));
  1295. X
  1296. X    req = DiskIOReq;
  1297. X    do {
  1298. X        req->iotd_Req.io_Command = ETD_READ;
  1299. X        req->iotd_Req.io_Data = (APTR)sec->sec_Data;
  1300. X        req->iotd_Req.io_Offset = Disk.lowcyl + (long) sector * Disk.bps;
  1301. X        req->iotd_Req.io_Length = Disk.bps;
  1302. X        MyDoIO(req);
  1303. X    } while (req->iotd_Req.io_Error != 0 && RetryRwError(req));
  1304. X
  1305. X    StartTimer();
  1306. X
  1307. X    if (req->iotd_Req.io_Error == 0) {
  1308. X        return sec->sec_Data;
  1309. X    }
  1310. X    error = ERROR_NOT_A_DOS_DISK;
  1311. X    FreeCacheSector(sec);
  1312. X    }
  1313. X    return NULL;
  1314. X}
  1315. X
  1316. X#ifndef READONLY
  1317. X
  1318. Xbyte           *
  1319. XEmptySec(sector)
  1320. Xint        sector;
  1321. X{
  1322. X    byte       *buffer;
  1323. X    register struct CacheSec *sec;
  1324. X
  1325. X    if (sec = FindSecByNumber(sector)) {
  1326. X    sec->sec_Refcount++;
  1327. X
  1328. X    return sec->sec_Data;
  1329. X    }
  1330. X    if (sec = NewCacheSector()) {
  1331. X    sec->sec_Number = sector;
  1332. X    sec->sec_Refcount = 1;
  1333. X
  1334. X    return sec->sec_Data;
  1335. X    }
  1336. X
  1337. X    return NULL;
  1338. X}
  1339. X
  1340. Xvoid
  1341. XPutSec(sector, data)
  1342. Xint        sector;
  1343. Xbyte           *data;
  1344. X{
  1345. X    register struct IOExtTD *req;
  1346. X
  1347. X    debug(("PutSec %d\n", sector));
  1348. X
  1349. X    req = DiskIOReq;
  1350. X    do {
  1351. X    req->iotd_Req.io_Command = ETD_WRITE;
  1352. X    req->iotd_Req.io_Data = (APTR) data;
  1353. X    req->iotd_Req.io_Offset = Disk.lowcyl + (long) sector * Disk.bps;
  1354. X    req->iotd_Req.io_Length = Disk.bps;
  1355. X    MyDoIO(req);
  1356. X    } while (req->iotd_Req.io_Error != 0 && RetryRwError(req));
  1357. X
  1358. X    StartTimer();
  1359. X}
  1360. X
  1361. X#endif
  1362. X
  1363. X/*
  1364. X * Unlock a cached sector. When the usage count drops to zero, which
  1365. X * implies it is not dirty, and we are over our cache quota, the sector is
  1366. X * freed. Otherwise we keep it for re-use.
  1367. X */
  1368. X
  1369. Xvoid
  1370. XFreeSec(buffer)
  1371. Xbyte           *buffer;
  1372. X{
  1373. X    register struct CacheSec *sec;
  1374. X
  1375. X    if (sec = FindSecByBuffer(buffer)) {
  1376. X    if (--sec->sec_Refcount == 0) { /* Implies not SEC_DIRTY */
  1377. X        if (CurrentCache > MaxCache) {
  1378. X        FreeCacheSector(sec);
  1379. X        }
  1380. X    }
  1381. X    }
  1382. X}
  1383. X
  1384. X#ifndef READONLY
  1385. X
  1386. Xvoid
  1387. XMarkSecDirty(buffer)
  1388. Xbyte           *buffer;
  1389. X{
  1390. X    register struct CacheSec *sec;
  1391. X
  1392. X    if (sec = FindSecByBuffer(buffer)) {
  1393. X    sec->sec_Refcount |= SEC_DIRTY;
  1394. X    DelayState |= DELAY_DIRTY;
  1395. X    StartTimer();
  1396. X    }
  1397. X}
  1398. X
  1399. X/*
  1400. X * Write out the FAT. Called from MSUpdate(), so don't call it again from
  1401. X * here. Don't use precious cache space for it; you could say it has its
  1402. X * own private cache already.
  1403. X */
  1404. X
  1405. Xvoid
  1406. XWriteFat()
  1407. X{
  1408. X    register int    fat,
  1409. X            sec;
  1410. X    int         disksec = Disk.res;      /* First FAT, first sector */
  1411. X
  1412. X    /* Write all FATs */
  1413. X    for (fat = 0; fat < Disk.nfats; fat++) {
  1414. X    for (sec = 0; sec < Disk.spf; sec++) {
  1415. X        PutSec(disksec++, Fat + sec * Disk.bps);
  1416. X        /* return;           /* Fat STILL dirty! */
  1417. X    }
  1418. X    }
  1419. X    FatDirty = FALSE;
  1420. X}
  1421. X
  1422. X#endif
  1423. X
  1424. Xint
  1425. XReadBootBlock()
  1426. X{
  1427. X    int protstatus;
  1428. X
  1429. X    debug(("ReadBootBlock\n"));
  1430. X    FreeFat();                  /* before disk parameters change */
  1431. X    TDClear();
  1432. X
  1433. X    if ((protstatus = TDProtStatus()) >= 0) {
  1434. X    TDChangeNum();
  1435. X    debug(("Changenumber = %ld\n", DiskIOReq->iotd_Count));
  1436. X    if (Word8086 = GetSec(0)) {
  1437. X        word bps;
  1438. X
  1439. X        /* 8086 ml for a jump */
  1440. X        if (Word8086[0] != 0xE9 && Word8086[0] != 0xEB) {
  1441. X        goto nodisk;
  1442. X        }
  1443. X        bps = Get8086Word(0x0b);
  1444. X        Disk.spc = Word8086[0x0d];
  1445. X        Disk.res = Get8086Word(0x0e);
  1446. X        Disk.nfats = Word8086[0x10];
  1447. X        Disk.ndirs = Get8086Word(0x11);
  1448. X        Disk.nsects = Get8086Word(0x13);
  1449. X        Disk.media = Word8086[0x15];
  1450. X        Disk.spf = Get8086Word(0x16);
  1451. X        Disk.spt = Get8086Word(0x18);
  1452. X        Disk.nsides = Get8086Word(0x1a);
  1453. X        Disk.nhid = Get8086Word(0x1c);
  1454. X        FreeSec(Word8086);
  1455. X
  1456. X        /*
  1457. X         *    Maybe the sector size just changed. Who knows?
  1458. X         */
  1459. X        if (Disk.bps != bps) {
  1460. X        FreeCacheList();
  1461. X        Disk.bps = bps;
  1462. X        InitCacheList();
  1463. X        }
  1464. X
  1465. X        Disk.ndirsects = (Disk.ndirs * MS_DIRENTSIZE) / Disk.bps;
  1466. X        Disk.rootdir = Disk.res + Disk.spf * Disk.nfats;
  1467. X        Disk.datablock = Disk.rootdir + Disk.ndirsects;
  1468. X        Disk.start = Disk.datablock - MS_FIRSTCLUST * Disk.spc;
  1469. X        /* Available clusters are 2..maxclust in secs start..nsects-1 */
  1470. X        Disk.maxclst = (Disk.nsects - Disk.start) / Disk.spc - 1;
  1471. X        Disk.bpc = Disk.bps * Disk.spc;
  1472. X        Disk.vollabel = FakeRootDirEntry;
  1473. X/*        Disk.fat16bits = Disk.nsects > 20740;   /* DOS3.2 magic value */
  1474. X        Disk.fat16bits = Disk.maxclst > 0xFF6;  /* DOS3.0 magic value */
  1475. X
  1476. X        debug(("%x\tbytes per sector\n", Disk.bps));
  1477. X        debug(("%x\tsectors per cluster\n", Disk.spc));
  1478. X        debug(("%x\treserved blocks\n", Disk.res));
  1479. X        debug(("%x\tfats\n", Disk.nfats));
  1480. X        debug(("%x\tdirectory entries\n", Disk.ndirs));
  1481. X        debug(("%x\tsectors\n", Disk.nsects));
  1482. X        debug(("%x\tmedia byte\n", Disk.media));
  1483. X        debug(("%x\tsectors per FAT\n", Disk.spf));
  1484. X        debug(("%x\tsectors per track\n", Disk.spt));
  1485. X        debug(("%x\tsides\n", Disk.nsides));
  1486. X        debug(("%x\thidden sectors\n", Disk.nhid));
  1487. X
  1488. X        debug(("%x\tdirectory sectors\n", Disk.ndirsects));
  1489. X        debug(("%x\troot dir block\n", Disk.rootdir));
  1490. X        debug(("%x\tblock for (imaginary) cluster 0\n", Disk.start));
  1491. X        debug(("%x\tfirst data block\n", Disk.datablock));
  1492. X        debug(("%x\tclusters total\n", Disk.maxclst));
  1493. X        debug(("%x\tbytes per cluster\n", Disk.bpc));
  1494. X        debug(("%x\t16-bits FAT?\n", Disk.fat16bits));
  1495. X
  1496. X        IDDiskType = ID_DOS_DISK;
  1497. X#ifdef READONLY
  1498. X        IDDiskState = ID_WRITE_PROTECTED;
  1499. X#else
  1500. X        if (protstatus > 0)
  1501. X        IDDiskState = ID_WRITE_PROTECTED;
  1502. X        else
  1503. X        IDDiskState = ID_VALIDATED;
  1504. X#endif
  1505. X
  1506. X        if (Disk.nsects / (MS_SPT * Disk.nsides) <= 40)
  1507. X        DiskIOReq->iotd_Req.io_Flags |= IOMDF_40TRACKS;
  1508. X        else
  1509. X        DiskIOReq->iotd_Req.io_Flags &= ~IOMDF_40TRACKS;
  1510. X
  1511. X        GetFat();
  1512. X    } else {
  1513. X        debug(("Can't read %d.\n", DiskIOReq->iotd_Req.io_Error));
  1514. X    nodisk:
  1515. X        FreeCacheList();
  1516. X        error = ERROR_NO_DISK;
  1517. X        IDDiskType = ID_UNREADABLE_DISK;
  1518. X        IDDiskState = ID_WRITE_PROTECTED;
  1519. X    }
  1520. X    }
  1521. X#ifdef DEBUG
  1522. X    else debug(("No disk inserted %d.\n", DiskIOReq->iotd_Req.io_Error));
  1523. X#endif
  1524. X    return 1;
  1525. X}
  1526. X
  1527. X/*
  1528. X * We try to identify the disk currently in the drive, trying to find the
  1529. X * volume label in the first directory block.
  1530. X */
  1531. X
  1532. Xint
  1533. XIdentifyDisk(name, date)
  1534. Xchar           *name;        /* Should be at least 32 characters */
  1535. Xstruct DateStamp *date;
  1536. X{
  1537. X    debug(("IdentifyDisk\n"));
  1538. X    ReadBootBlock();            /* Also sets default vollabel */
  1539. X
  1540. X    if (IDDiskType == ID_DOS_DISK) {
  1541. X    byte           *dirblock;
  1542. X    register struct MsDirEntry *dirent;
  1543. X
  1544. X    if (dirblock = GetSec(Disk.rootdir)) {
  1545. X        dirent = (struct MsDirEntry *) dirblock;
  1546. X
  1547. X        while ((byte *) dirent < &dirblock[Disk.bps]) {
  1548. X        if (dirent->msd_Attributes & ATTR_VOLUMELABEL) {
  1549. X            Disk.vollabel.de_Msd = *dirent;
  1550. X            Disk.vollabel.de_Sector = Disk.rootdir;
  1551. X            Disk.vollabel.de_Offset = (byte *) dirent - dirblock;
  1552. X            OtherEndianMsd(&Disk.vollabel.de_Msd);
  1553. X            Disk.vollabel.de_Msd.msd_Cluster = 0;    /* to be sure */
  1554. X            break;
  1555. X        }
  1556. X        dirent++;
  1557. X        }
  1558. X        strncpy(name, Disk.vollabel.de_Msd.msd_Name, 8 + 3);
  1559. X        name[8 + 3] = '\0';
  1560. X        ZapSpaces(name, name + 8 + 3);
  1561. X        ToDateStamp(date, Disk.vollabel.de_Msd.msd_Date,
  1562. X            Disk.vollabel.de_Msd.msd_Time);
  1563. X        debug(("Disk is called '%s'\n", name));
  1564. X
  1565. X        FreeSec(dirblock);
  1566. X
  1567. X        return 0;
  1568. X    }
  1569. X    }
  1570. X    return 1;
  1571. X}
  1572. X
  1573. X/*
  1574. X * Remove the disk change SoftInt. The V1.2 / V1.3 version is broken, so
  1575. X * we use a workaround. The correct thing to do is shown but not used.
  1576. X */
  1577. X
  1578. Xvoid
  1579. XTDRemChangeInt()
  1580. X{
  1581. X    if (DiskChangeReq) {
  1582. X    register struct IOExtTD *req = DiskIOReq;
  1583. X
  1584. X#if 0                /* V1.2 and V1.3 have a broken
  1585. X                 * TD_REMCHANGEINT */
  1586. X    req->iotd_Req.io_Command = TD_REMCHANGEINT;
  1587. X    req->iotd_Req.io_Data = (void *) DiskChangeReq;
  1588. X    MyDoIO(req);
  1589. X    WaitIO(DiskChangeReq);
  1590. X#else
  1591. X    Forbid();
  1592. X    Remove(DiskChangeReq);
  1593. X    Permit();
  1594. X#endif
  1595. X    DeleteExtIO(DiskChangeReq);
  1596. X    DiskChangeReq = NULL;
  1597. X    }
  1598. X}
  1599. X
  1600. X/*
  1601. X * Set the disk change SoftInt. Return nonzero on failure.
  1602. X */
  1603. X
  1604. Xint
  1605. XTDAddChangeInt(interrupt)
  1606. Xstruct Interrupt *interrupt;
  1607. X{
  1608. X    register struct IOExtTD *req = DiskIOReq;
  1609. X
  1610. X    if (DiskChangeReq) {
  1611. X    TDRemChangeInt();
  1612. X    }
  1613. X    DiskChangeReq = (void *)CreateExtIO(DiskReplyPort,
  1614. X                     (long) sizeof (*DiskChangeReq));
  1615. X    if (DiskChangeReq) {
  1616. X    /* Clone IO request part */
  1617. X    DiskChangeReq->io_Device = req->iotd_Req.io_Device;
  1618. X    DiskChangeReq->io_Unit = req->iotd_Req.io_Unit;
  1619. X    DiskChangeReq->io_Command = TD_ADDCHANGEINT;
  1620. X    DiskChangeReq->io_Data = (void *) interrupt;
  1621. X    SendIO(DiskChangeReq);
  1622. X
  1623. X    return 0;
  1624. X    }
  1625. X    return 1;
  1626. X}
  1627. X
  1628. X/*
  1629. X * Get the current disk change number. Necessary for ETD_ commands. Makes
  1630. X * absolutely sure nobody can change the disk without us noticing it.
  1631. X */
  1632. X
  1633. Xint
  1634. XTDChangeNum()
  1635. X{
  1636. X    register struct IOExtTD *req = DiskIOReq;
  1637. X
  1638. X    req->iotd_Req.io_Command = TD_CHANGENUM;
  1639. X    MyDoIO(req);
  1640. X    req->iotd_Count = req->iotd_Req.io_Actual;
  1641. X
  1642. X    return req->iotd_Req.io_Actual;
  1643. X}
  1644. X
  1645. X/*
  1646. X * Get the current write protection state.
  1647. X *
  1648. X * Zero means writable, one means write protected, minus one means
  1649. X * no disk in drive.
  1650. X */
  1651. X
  1652. Xint
  1653. XTDProtStatus()
  1654. X{
  1655. X    register struct IOExtTD *req = DiskIOReq;
  1656. X
  1657. X    req->iotd_Req.io_Command = TD_PROTSTATUS;
  1658. X    MyDoIO(req);
  1659. X
  1660. X    if (req->iotd_Req.io_Error)
  1661. X    return -1;
  1662. X
  1663. X    return req->iotd_Req.io_Actual != 0;
  1664. X}
  1665. X
  1666. X/*
  1667. X * Switch the drive motor off. Return previous state. Don't use this when
  1668. X * you have allocated the disk via GetDrive().
  1669. X */
  1670. X
  1671. Xint
  1672. XTDMotorOff()
  1673. X{
  1674. X    register struct IOExtTD *req = DiskIOReq;
  1675. X
  1676. X    req->iotd_Req.io_Command = TD_MOTOR;
  1677. X    req->iotd_Req.io_Length = 0;
  1678. X    MyDoIO(req);
  1679. X
  1680. X    return req->iotd_Req.io_Actual;
  1681. X}
  1682. X
  1683. X/*
  1684. X * Clear all internal messydisk buffers.
  1685. X */
  1686. X
  1687. Xint
  1688. XTDClear()
  1689. X{
  1690. X    register struct IOExtTD *req = DiskIOReq;
  1691. X
  1692. X    req->iotd_Req.io_Command = CMD_CLEAR;
  1693. X
  1694. X    return MyDoIO(req);
  1695. X}
  1696. X
  1697. X#ifndef READONLY
  1698. X/*
  1699. X * Write out all internal messydisk buffers to the disk.
  1700. X */
  1701. X
  1702. Xint
  1703. XTDUpdate()
  1704. X{
  1705. X    register struct IOExtTD *req = DiskIOReq;
  1706. X
  1707. X    req->iotd_Req.io_Command = ETD_UPDATE;
  1708. X
  1709. X    return MyDoIO(req);
  1710. X}
  1711. X#endif
  1712. X
  1713. Xint
  1714. XMyDoIO(ioreq)
  1715. Xregister struct IOStdReq *ioreq;
  1716. X{
  1717. X    ioreq->io_Flags |= IOF_QUICK;    /* Preserve IOMDF_40TRACKS */
  1718. X    BeginIO(ioreq);
  1719. X    return WaitIO(ioreq);
  1720. X}
  1721. END_OF_FILE
  1722. if test 19261 -ne `wc -c <'src/hansec.c'`; then
  1723.     echo shar: \"'src/hansec.c'\" unpacked with wrong size!
  1724. fi
  1725. # end of 'src/hansec.c'
  1726. fi
  1727. echo shar: End of archive 3 \(of 6\).
  1728. cp /dev/null ark3isdone
  1729. MISSING=""
  1730. for I in 1 2 3 4 5 6 ; do
  1731.     if test ! -f ark${I}isdone ; then
  1732.     MISSING="${MISSING} ${I}"
  1733.     fi
  1734. done
  1735. if test "${MISSING}" = "" ; then
  1736.     echo You have unpacked all 6 archives.
  1737.     rm -f ark[1-9]isdone
  1738. else
  1739.     echo You still need to unpack the following archives:
  1740.     echo "        " ${MISSING}
  1741. fi
  1742. ##  End of shell archive.
  1743. exit 0
  1744. -- 
  1745. Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
  1746. Mail comments to the moderator at <amiga-request@cs.odu.edu>.
  1747. Post requests for sources, and general discussion to comp.sys.amiga.
  1748.